<template>
  <view
    v-show="url"
    :mode="modeValue"
    :change:mode="mwx.changeMode"
    :rotate="rotate"
    :change:rotate="mwx.changeRotate"
  >
    <!-- #ifdef MP-WEIXIN -->
    <canvas
      type="2d"
      class="canvas"
      :style="{ width: target.width + 'px', height: target.height + 'px' }"
    ></canvas>
    <!-- #endif -->
    <!-- #ifdef APP-PLUS || H5 -->
    <canvas
      :canvas-id="canvasId"
      :style="{ width: target.width + 'px', height: target.height + 'px' }"
    ></canvas>
    <!-- #endif -->
    <view class="panel">
      <view
        class="body"
        @touchstart="mwx.touchstart"
        @touchmove="mwx.touchmove"
        @touchend="mwx.touchend"
        @touchcancel="mwx.touchcancel"
        @wheel="onWheel"
      >
        <view
          class="image-wrap"
          :class="{ transit: transit }"
          :change:rect="mwx.changeImage"
          :rect="image"
        >
          <image class="image" :class="{ transit: transit }" :src="url" @load="imageLoad" />
        </view>
        <view class="mask"></view>
        <view
          class="frame"
          :class="{ transit: transit }"
          :change:rect="mwx.changeFrame"
          :rect="frame"
        >
          <view class="rect">
            <view class="image-rect" :class="{ transit: transit }">
              <image class="image" :class="{ transit: transit }" :src="url" />
            </view>
          </view>
          <view class="line-one"></view>
          <view class="line-two"></view>
          <view class="line-three"></view>
          <view class="line-four"></view>
          <view class="frame-left-top" @touchstart="mwx.touchstart"></view>
          <view class="frame-left-bottom" @touchstart="mwx.touchstart"></view>
          <view class="frame-right-top" @touchstart="mwx.touchstart"></view>
          <view class="frame-right-bottom" @touchstart="mwx.touchstart"></view>
        </view>
      </view>
      <view class="toolbar">
        <view @tap="onCancel" class="btn-cancel">取消</view>
        <view @tap="rotateAngle" class="btn-rotate">旋转</view>
        <view @tap="onok" class="btn-ok">确定</view>
      </view>
    </view>
  </view>
</template>

<script>
/**
 * @property {String} mode 模式
 *  @value fixed 固定模式，裁剪出固定大小
 *  @value ratio 等比模式，宽高等比缩放
 *  @value free 自由模式，不限制宽高比
 * @property {String} url 图片路径
 * @property {Number} width 宽度
 * @property {Number} height 高度
 * @property {Number} maxWidth 最大宽带
 * @property {Number} minHeight 最大高度
 */
export default {
  props: {
    mode: {
      type: String,
      default: 'free', // 默认模式为自由模式
    },
    url: {
      type: String,
      default: '', // 默认图片路径为空
    },
    width: {
      type: Number,
      default: 200, // 默认宽度为200
    },
    height: {
      type: Number,
      default: 200, // 默认高度为200
    },
    maxWidth: {
      type: Number,
      default: 1024, // 默认最大宽度为1024
    },
    maxHeight: {
      type: Number,
      default: 1024, // 默认最大高度为1024
    },
    watermark: {
      type: String,
      default: '', // 默认水印为空
    },
    watermarkType: {
      type: Number,
      default: 1, // 默认水印类型为1
    },
  },
  data() {
    return {
      canvasId: Math.random().toString(36).slice(-6), // 生成随机的canvasId
      real: {
        width: 100, // 实际图片宽度
        height: 100, // 实际图片高度
      },
      target: {
        width: 100, // 目标宽度
        height: 100, // 目标高度
      },
      body: {
        width: 100, // 画布宽度
        height: 100, // 画布高度
      },
      frame: {
        left: 50, // 框左边距
        top: 50, // 框上边距
        width: 200, // 框宽度
        height: 300, // 框高度
      },
      image: {
        left: 20, // 图片左边距
        top: 20, // 图片上边距
        width: 300, // 图片宽度
        height: 400, // 图片高度
      },
      rotate: 0, // 图片旋转角度
      transit: false, // 是否过渡
      modeValue: '', // 模式值
    }
  },
  methods: {
    imageLoad(event) {
      uni.getImageInfo({
        src: this.url,
        success: (rst) => {
          this.real.width = rst.width // 获取实际图片宽度
          this.real.height = rst.height // 获取实际图片高度
          this.target = {} // 重置目标
          var query = uni.createSelectorQuery().in(this)
          query
            .select('.body')
            .boundingClientRect((data) => {
              this.body.width = data.width // 获取画布宽度
              this.body.height = data.height // 获取画布高度
              this.init() // 初始化
            })
            .exec()
        },
      })
    },
    init() {
      this.modeValue = this.mode // 设置模式值
      this.rotate = 0 // 重置旋转角度
      var rate = this.width / this.height // 计算宽高比
      var width = this.body.width * 0.7 // 计算宽度
      var height = this.body.height * 0.7 // 计算高度
      if (width / height > rate) {
        width = height * rate // 调整宽度
      } else {
        height = width / rate // 调整高度
      }
      var left = (this.body.width - width) / 2 // 计算左边距
      var top = (this.body.height - height) / 2 // 计算上边距
      this.frame = {
        left: left,
        top: top,
        width: width,
        height: height,
      }
      rate = this.real.width / this.real.height // 计算实际宽高比
      width = this.frame.width // 获取框宽度
      height = this.frame.height // 获取框高度
      if (width / height > rate) {
        height = width / rate // 调整高度
      } else {
        width = height * rate // 调整宽度
      }
      left = (this.frame.width - width) / 2 + this.frame.left // 计算左边距
      top = (this.frame.height - height) / 2 + this.frame.top // 计算上边距
      this.image = {
        left: left,
        top: top,
        width: width,
        height: height,
      }
    },
    async updateData(data) {
      this.frame = data.frame // 更新框数据
      this.image = data.image // 更新图片数据
      await this.$nextTick() // 等待下一个 DOM 更新
      this.trimImage() // 裁剪图片
    },
    trimImage() {
      var rate = this.frame.width / this.frame.height // 计算框的宽高比
      var width = this.body.width * 0.7 // 计算宽度
      var height = this.body.height * 0.7 // 计算高度
      if (width / height > rate) {
        width = height * rate // 调整宽度
      } else {
        height = width / rate // 调整高度
      }
      var left = (this.body.width - width) / 2 // 计算左边距
      var top = (this.body.height - height) / 2 // 计算上边距
      var mul = width / this.frame.width // 计算缩放比例
      var ox = this.frame.left - this.image.left // 计算图片的偏移量
      var oy = this.frame.top - this.image.top // 计算图片的偏移量
      this.frame = {
        left: left,
        top: top,
        width: width,
        height: height,
      }
      width = this.image.width * mul // 更新图片宽度
      height = this.image.height * mul // 更新图片高度
      left = this.frame.left - ox * mul // 更新图片左边距
      top = this.frame.top - oy * mul // 更新图片上边距
      this.image = {
        left: left,
        top: top,
        width: width,
        height: height,
      }
      if (mul != 1) {
        this.transit = true // 设置过渡为真
        setTimeout(() => {
          this.transit = false // 300ms后重置过渡
        }, 300)
      }
    },
    rotateAngle() {
      this.rotate -= 90 // 旋转角度减90
      var width = this.image.height // 获取图片高度
      var height = this.image.width // 获取图片宽度
      var left = this.image.left // 获取图片左边距
      var top = this.image.top // 获取图片上边距
      var rate = width / height // 计算宽高比
      if (width < this.frame.width) {
        width = this.frame.width // 调整宽度
        height = width / rate // 调整高度
      }
      if (height < this.frame.height) {
        height = this.frame.height // 调整高度
        width = height * rate // 调整宽度
      }
      if (left > this.frame.left) {
        left = this.frame.left // 调整左边距
      }
      if (top > this.frame.top) {
        top = this.frame.top // 调整上边距
      }
      if (left + width < this.frame.left + this.frame.width) {
        left = this.frame.left + this.frame.width - width // 调整左边距
      }
      if (top + height < this.frame.top + this.frame.height) {
        top = this.frame.top + this.frame.height - height // 调整上边距
      }
      this.image = {
        left: left,
        top: top,
        width: width,
        height: height,
      }
      this.transit = true // 设置过渡为真
      setTimeout(() => {
        this.transit = false // 300ms后重置过渡
      }, 300)
    },
    onok() {
      // #ifdef MP-WEIXIN
      this.cropWx() // 微信平台裁剪
      // #endif
      // #ifdef APP-PLUS || H5
      this.cropAppH5() // APP和H5平台裁剪
      // #endif
    },
    onCancel() {
      this.$emit('cancel') // 触发取消事件
    },
    async cropWx() {
      var mx = this.computeMatrix() // 计算矩阵
      this.target = {
        width: mx.tw,
        height: mx.th,
      }
      var canvas = await new Promise((resolve) => {
        uni
          .createSelectorQuery()
          .in(this)
          .select('.canvas')
          .fields({ node: true })
          .exec((rst) => {
            var node = rst[0].node // 获取canvas节点
            resolve(node)
          })
      })
      canvas.width = mx.tw // 设置canvas宽度
      canvas.height = mx.th // 设置canvas高度
      uni.showLoading({
        title: '处理中', // 显示加载提示
      })
      await new Promise((resolve) => {
        setTimeout(resolve, 200) // 延迟200ms
      })
      var context = canvas.getContext('2d') // 获取canvas上下文
      var image = canvas.createImage() // 创建图片对象
      await new Promise((resolve, reject) => {
        image.onload = resolve // 图片加载成功
        image.onerror = reject // 图片加载失败
        image.src = this.url // 设置图片源
      })
      context.save() // 保存当前状态
      context.rotate((this.rotate * Math.PI) / 180) // 旋转canvas
      context.drawImage(image, mx.sx, mx.sy, mx.sw, mx.sh, mx.dx, mx.dy, mx.dw, mx.dh) // 绘制图片
      context.restore() // 恢复状态
      wx.canvasToTempFilePath({
        canvas: canvas,
        // destWidth: mx.tw,
        // destHeight: mx.th,
        success: (rst) => {
          var path = rst.tempFilePath // 获取临时文件路径
          this.$emit('ok', {
            path: path, // 触发成功事件
          })
        },
        complete: () => {
          uni.hideLoading() // 隐藏加载提示
        },
      })
    },
    async cropAppH5() {
      var mx = this.computeMatrix() // 计算矩阵
      this.target = {
        width: mx.tw,
        height: mx.th,
      }
      console.log(mx) // 打印矩阵信息
      uni.showLoading({
        title: '处理中', // 显示加载提示
      })
      await new Promise((resolve) => {
        setTimeout(() => {
          resolve() // 延迟200ms
        }, 200)
      })
      var context = uni.createCanvasContext(this.canvasId, this) // 创建canvas上下文

      context.save() // 保存当前状态
      context.rotate((this.rotate * Math.PI) / 180) // 旋转canvas
      context.drawImage(this.url, mx.sx, mx.sy, mx.sw, mx.sh, mx.dx, mx.dy, mx.dw, mx.dh) // 绘制图片

      if (this.watermark) {
        this.toWatermark(context, mx) // 添加水印
      }

      context.restore() // 恢复状态
      await new Promise((resolve) => {
        context.draw(false, () => {
          resolve() // 绘制完成
        })
      })

      uni.canvasToTempFilePath(
        {
          canvasId: this.canvasId,
          destWidth: mx.tw,
          destHeight: mx.th,
          success: (rst) => {
            var path = rst.tempFilePath // 获取临时文件路径
            // #ifdef H5
            var base64 = path // 获取base64编码
            path = this.parseBlob(path) // 解析为Blob
            this.$emit('ok', {
              path: path,
              base64: base64, // 触发成功事件
            })
            // #endif
            // #ifdef APP-PLUS
            this.$emit('ok', {
              path: path, // 触发成功事件
            })
            // #endif
          },
          complete: () => {
            uni.hideLoading() // 隐藏加载提示
          },
        },
        this,
      )
    },
    toWatermark(context, mx) {
      // 添加水印的逻辑
      if (this.watermarkType == 1) {
        let min = mx.tw > mx.th ? mx.tw : mx.th
        let fz = Math.trunc(min / 10)
        let fzs = fz + 'px Arial'
        console.log(fzs)

        // 设置水印的样式 normal bold 36px Arial,sans-serif
        context.font = fzs
        context.fillStyle = 'rgba(0, 0, 0, 0.4)' // 设置水印颜色
        context.textAlign = 'center' // 设置文本对齐方式
        context.textBaseline = 'middle' // 设置文本基线

        // 计算水印文本的位置
        const x = mx.tw / 2
        const y = mx.th / 2

        // 倾斜角度
        const angle = -30
        const angleInRad = angle * (Math.PI / 180)

        // 平移到指定位置
        context.translate(x, y)

        // 旋转角度
        context.rotate(angleInRad)

        // 绘制水印文本
        context.fillText(this.watermark, 0, 0)

        // 绘制上下两条线
        context.beginPath()
        let leg = (mx.th > mx.tw ? mx.th : mx.tw) - fz * 2
        context.moveTo(-leg / 2, -fz)
        context.lineTo(leg / 2, -fz)
        context.moveTo(-leg / 2, fz)
        context.lineTo(leg / 2, fz)
        context.strokeStyle = 'rgba(0, 0, 0, 0.3)' // 设置线条颜色
        context.lineWidth = Math.trunc(fz / 25) // 设置线条宽度
        context.stroke()
      }
      if (this.watermarkType == 2) {
        let min = mx.tw > mx.th ? mx.tw : mx.th
        let fz = Math.trunc(min / 15)
        let fzs = fz + 'px Arial'
        console.log(fzs)

        // 设置水印的样式 normal bold 36px Arial,sans-serif
        context.font = fzs
        context.fillStyle = 'rgba(0, 0, 0, 0.4)' // 设置水印颜色
        context.textAlign = 'left' // 设置文本对齐方式
        context.textBaseline = 'middle' // 设置文本基线

        // 计算水印文本的位置
        const x = mx.tw / 2
        const y = mx.th / 2

        // 平移到指定位置
        context.translate(50, mx.th - fz)

        // 绘制水印文本
        context.fillText(this.watermark, 0, 0)
      }
      if (this.watermarkType == 3) {
        // 水印类型3的逻辑（未实现）
      }
    },
    computeMatrix() {
      // 添加空值保护
      const safeImage = this.image || { width: 0, height: 0 }
      const safeFrame = this.frame || { width: 0, height: 0 }

      let width = this.width || 0
      let height = this.height || 0

      // 修改点：将mul提取到函数顶部统一声明
      let mul = safeImage.width / (this.real.width || 1)

      if (this.rotate % 180 != 0) {
        mul = safeImage.height / (this.real.width || 1) // 使用相同变量
      }
      if (this.mode != 'fixed') {
        width = this.frame.width / mul // 计算框的宽度
        height = this.frame.height / mul // 计算框的高度
      }
      var rate = width / height // 计算宽高比
      if (width > this.maxWidth) {
        width = this.maxWidth // 限制最大宽度
        height = width / rate // 根据宽高比调整高度
      }
      if (height > this.maxHeight) {
        height = this.maxHeight // 限制最大高度
        width = height * rate // 根据宽高比调整宽度
      }
      var sx = (this.frame.left - this.image.left) / mul // 计算x坐标
      var sy = (this.frame.top - this.image.top) / mul // 计算y坐标
      var sw = this.frame.width / mul // 计算框的宽度
      var sh = this.frame.height / mul // 计算框的高度
      var ox = sx + sw / 2 // 计算中心x坐标
      var oy = sy + sh / 2 // 计算中心y坐标
      if (this.rotate % 180 != 0) {
        var temp = sw // 交换宽高
        sw = sh
        sh = temp
      }
      var angle = this.rotate % 360 // 计算旋转角度
      if (angle < 0) {
        angle += 360 // 确保角度为正
      }
      if (angle == 270) {
        var x = this.real.width - oy // 计算旋转后的x坐标
        var y = ox // 计算旋转后的y坐标
        ox = x // 更新ox
        oy = y // 更新oy
      }
      if (angle == 180) {
        var x = this.real.width - ox // 计算旋转后的x坐标
        var y = this.real.height - oy // 计算旋转后的y坐标
        ox = x // 更新ox
        oy = y // 更新oy
      }
      if (angle == 90) {
        var x = oy // 计算旋转后的x坐标
        var y = this.real.height - ox // 计算旋转后的y坐标
        ox = x // 更新ox
        oy = y // 更新oy
      }
      sx = ox - sw / 2 // 更新sx
      sy = oy - sh / 2 // 更新sy
      var dr = { x: 0, y: 0, w: width, h: height } // 初始化目标矩形
      dr = this.parseRect(dr, -this.rotate) // 解析矩形
      return {
        tw: width, // 返回目标宽度
        th: height, // 返回目标高度
        sx: sx, // 返回源x坐标
        sy: sy, // 返回源y坐标
        sw: sw, // 返回源宽度
        sh: sh, // 返回源高度
        dx: dr.x, // 返回目标x坐标
        dy: dr.y, // 返回目标y坐标
        dw: dr.w, // 返回目标宽度
        dh: dr.h, // 返回目标高度
      }
    },
    parsePoint(point, angle) {
      var result = {}
      result.x =
        point.x * Math.cos((angle * Math.PI) / 180) - point.y * Math.sin((angle * Math.PI) / 180) // 计算旋转后的x坐标
      result.y =
        point.y * Math.cos((angle * Math.PI) / 180) + point.x * Math.sin((angle * Math.PI) / 180) // 计算旋转后的y坐标
      return result // 返回结果
    },
    parseRect(rect, angle) {
      var x1 = rect.x // 获取矩形左上角x坐标
      var y1 = rect.y // 获取矩形左上角y坐标
      var x2 = rect.x + rect.w // 获取矩形右下角x坐标
      var y2 = rect.y + rect.h // 获取矩形右下角y坐标
      var p1 = this.parsePoint({ x: x1, y: y1 }, angle) // 解析左上角
      var p2 = this.parsePoint({ x: x2, y: y2 }, angle) // 解析右下角
      var result = {}
      result.x = Math.min(p1.x, p2.x) // 获取最小x坐标
      result.y = Math.min(p1.y, p2.y) // 获取最小y坐标
      result.w = Math.abs(p2.x - p1.x) // 获取宽度
      result.h = Math.abs(p2.y - p1.y) // 获取高度
      return result // 返回结果
    },
    parseBlob(base64) {
      var arr = base64.split(',') // 分割base64字符串
      var mime = arr[0].match(/:(.*?);/)[1] // 获取MIME类型
      var bstr = atob(arr[1]) // 解码base64
      var n = bstr.length // 获取字符串长度
      var u8arr = new Uint8Array(n) // 创建Uint8Array
      for (var i = 0; i < n; i++) {
        u8arr[i] = bstr.charCodeAt(i) // 填充Uint8Array
      }
      var url = URL || webkitURL // 获取URL对象
      return url.createObjectURL(new Blob([u8arr], { type: mime })) // 创建Blob URL
    },
    onWheel(event) {
      event.preventDefault() // 阻止默认滚动行为
      const scaleAmount = 0.1 // 每次滚动放大或缩小的比例
      const delta = event.deltaY // 获取滚动的距离

      if (delta > 0) {
        // 向下滚动，缩小
        this.image.width *= 1 - scaleAmount // 缩小图片宽度
        this.image.height *= 1 - scaleAmount // 缩小图片高度
      } else {
        // 向上滚动，放大
        this.image.width *= 1 + scaleAmount // 放大图片宽度
        this.image.height *= 1 + scaleAmount // 放大图片高度
      }

      // 更新样式
      this.updateStyle() // 更新样式
    },
  },
}
</script>

<script module="mwx" lang="wxs">
var mode = ""; // 模式
var rotate = 0; // 旋转角度
var image = {
	left: 0, // 图片左边距
	top: 0, // 图片上边距
	width: 0, // 图片宽度
	height: 0 // 图片高度
};
var frame = {
	left: 0, // 框左边距
	top: 0, // 框上边距
	width: 0, // 框宽度
	height: 0 // 框高度
};
var touches = []; // 触摸事件数组
var touchType = ""; // 触摸类型
var start = {
	frame: {
		left: 0, // 起始框左边距
		top: 0, // 起始框上边距
		width: 0, // 起始框宽度
		height: 0 // 起始框高度
	},
	image: {
		left: 0, // 起始图片左边距
		top: 0, // 起始图片上边距
		width: 0, // 起始图片宽度
		height: 0 // 起始图片高度
	}
};
function changeMode(value) {
       if (null == value) {
           return; // 如果值为空，返回
       }
	mode = value; // 更新模式
}
function changeRotate(value, old, oi, instance) {
       if (null == value) {
           return; // 如果值为空，返回
       }
	rotate = value; // 更新旋转角度
	delayUpdateStyle(oi); // 延迟更新样式
}
function changeImage(value, old, oi, instance) {
       if (null == value) {
           return; // 如果值为空，返回
       }
	image = value; // 更新图片
	delayUpdateStyle(oi); // 延迟更新样式
}
function changeFrame(value, old, oi, instance) {
       if (null == value) {
           return; // 如果值为空，返回
       }
	frame = value; // 更新框
	delayUpdateStyle(oi); // 延迟更新样式
}
   function delayUpdateStyle(oi) {
       // #ifdef APP-PLUS || H5
       setTimeout(() => {
           updateStyle(oi); // 延迟更新样式
       });
       // #endif
       // #ifdef MP-WEIXIN
       updateStyle(oi); // 立即更新样式
       // #endif
   }
function touchstart(event, oi) {
	// #ifdef APP-PLUS || H5
       if (event.preventDefault) {
           event.preventDefault(); // 阻止默认事件
       }
       if (event.stopPropagation) {
           event.stopPropagation(); // 阻止事件传播
       }
	// #endif
	touches = event.touches; // 获取触摸事件
	var instance = event.instance; // 获取事件实例
	if (instance.hasClass("body")) {
		touchType = "body"; // 触摸类型为body
	} else if (instance.hasClass("frame-left-top")) {
		touchType = "left-top"; // 触摸类型为左上角
	} else if (instance.hasClass("frame-left-bottom")) {
		touchType = "left-bottom"; // 触摸类型为左下角
	} else if (instance.hasClass("frame-right-top")) {
		touchType = "right-top"; // 触摸类型为右上角
	} else if (instance.hasClass("frame-right-bottom")) {
		touchType = "right-bottom"; // 触摸类型为右下角
	}
	start.frame.left = frame.left; // 记录起始框左边距
	start.frame.top = frame.top; // 记录起始框上边距
	start.frame.width = frame.width; // 记录起始框宽度
	start.frame.height = frame.height; // 记录起始框高度
	start.image.left = image.left; // 记录起始图片左边距
	start.image.top = image.top; // 记录起始图片上边距
	start.image.width = image.width; // 记录起始图片宽度
	start.image.height = image.height; // 记录起始图片高度
	return false; // 返回false以阻止默认行为
}
function touchmove(event, oi) {
	// #ifdef APP-PLUS || H5
	if (event.preventDefault) {
		event.preventDefault(); // 阻止默认事件
	}
	if (event.stopPropagation) {
		event.stopPropagation(); // 阻止事件传播
	}
	// #endif
	var instance = event.instance; // 获取事件实例
	if (touches.length == 1) {
		if (touchType == "body") {
			moveImage(touches[0], event.touches[0], oi); // 移动图片
		} else {
			scaleFrame(touches[0], event.touches[0], oi); // 缩放框
		}
	} else if (touches.length == 2 && event.touches.length == 2) {
		var ta = touches[0]; // 获取第一个触摸点
		var tb = touches[1]; // 获取第二个触摸点
		var tc = event.touches[0]; // 获取当前第一个触摸点
		var td = event.touches[1]; // 获取当前第二个触摸点
		if (ta.identifier != tc.identifier) {
			var temp = tc; // 交换触摸点
			tc = td;
			td = temp;
		}
		scaleImage(ta, tb, tc, td, oi); // 缩放图片
	}
}
function touchend(event, oi) {
	touches = []; // 清空触摸事件
	oi.callMethod("updateData", {frame: frame, image: image}); // 更新数据
}
function touchcancel(event, oi) {
	touches = []; // 清空触摸事件
	oi.callMethod("updateData", {frame: frame, image: image}); // 更新数据
}
function moveImage(ta, tb, oi) {
	var ax = tb.clientX - ta.clientX; // 计算x轴移动距离
	var ay = tb.clientY - ta.clientY; // 计算y轴移动距离
	image.left = start.image.left + ax; // 更新图片左边距
	image.top = start.image.top + ay; // 更新图片上边距
	var left = frame.left; // 获取框左边距
	var top = frame.top; // 获取框上边距
	var width = frame.width; // 获取框宽度
	var height = frame.height; // 获取框高度
	if (image.left > left) {
		image.left = left; // 限制图片左边距
	}
	if (image.top > top) {
		image.top = top; // 限制图片上边距
	}
	if (image.left + image.width < left + width) {
		image.left = left + width - image.width; // 限制图片右边距
	}
	if (image.top + image.height < top + height) {
		image.top = top + height - image.height; // 限制图片下边距
	}
	updateStyle(oi); // 更新样式
}
function scaleImage(ta, tb, tc, td, oi) {
	var x1 = ta.clientX; // 获取第一个触摸点x坐标
	var y1 = ta.clientY; // 获取第一个触摸点y坐标
	var x2 = tb.clientX; // 获取第二个触摸点x坐标
	var y2 = tb.clientY; // 获取第二个触摸点y坐标
	var x3 = tc.clientX; // 获取当前第一个触摸点x坐标
	var y3 = tc.clientY; // 获取当前第一个触摸点y坐标
	var x4 = td.clientX; // 获取当前第二个触摸点x坐标
	var y4 = td.clientY; // 获取当前第二个触摸点y坐标
	var ol = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); // 计算原始距离
	var el = Math.sqrt((x3 - x4) * (x3 - x4) + (y3 - y4) * (y3 - y4)); // 计算当前距离
	var ocx = (x1 + x2) / 2; // 计算原始中心x坐标
	var ocy = (y1 + y2) / 2; // 计算原始中心y坐标
	var ecx = (x3 + x4) / 2; // 计算当前中心x坐标
	var ecy = (y3 + y4) / 2; // 计算当前中心y坐标
	var ax = ecx - ocx; // 计算x轴移动距离
	var ay = ecy - ocy; // 计算y轴移动距离
	var scale = el / ol; // 计算缩放比例
	if (start.image.width * scale < frame.width) {
		scale = frame.width / start.image.width; // 限制缩放比例
	}
	if (start.image.height * scale < frame.height) {
		scale = frame.height / start.image.height; // 限制缩放比例
	}
	if (start.image.width * scale < frame.width) {
		scale = frame.width / start.image.width; // 限制缩放比例
	}
	image.left = start.image.left + ax - (ocx - start.image.left) * (scale - 1); // 更新图片左边距
	image.top = start.image.top + ay - (ocy - start.image.top) * (scale - 1); // 更新图片上边距
	image.width = start.image.width * scale; // 更新图片宽度
	image.height = start.image.height * scale; // 更新图片高度
	if (image.left > frame.left) {
		image.left = frame.left; // 限制图片左边距
	}
	if (image.top > frame.top) {
		image.top = frame.top; // 限制图片上边距
	}
	if (image.left + image.width < frame.left + frame.width) {
		image.left = frame.left + frame.width - image.width; // 限制图片右边距
	}
	if (image.top + image.height < frame.top + frame.height) {
		image.top = frame.top + frame.height - image.height; // 限制图片下边距
	}
	updateStyle(oi); // 更新样式
}
function scaleFrame(ta, tb, oi) {
	var ax = tb.clientX - ta.clientX; // 计算x轴移动距离
	var ay = tb.clientY - ta.clientY; // 计算y轴移动距离
	var x1 = start.frame.left; // 获取起始框左边距
	var y1 = start.frame.top; // 获取起始框上边距
	var x2 = start.frame.left + start.frame.width; // 获取起始框右下角x坐标
	var y2 = start.frame.top + start.frame.height; // 获取起始框右下角y坐标
	var cx1 = false; // 左上角标志
	var cy1 = false; // 左上角标志
	var cx2 = false; // 右下角标志
	var cy2 = false; // 右下角标志
	var mix = 30; // 最小缩放距离
	var rate = frame.width / frame.height; // 计算框的宽高比
	if (touchType == "left-top") {
		x1 += ax; // 更新左上角x坐标
		y1 += ay; // 更新左上角y坐标
		cx1 = true; // 设置左上角标志为真
		cy1 = true; // 设置左上角标志为真
	} else if (touchType == "left-bottom") {
		x1 += ax; // 更新左上角x坐标
		y2 += ay; // 更新右下角y坐标
		cx1 = true; // 设置左上角标志为真
		cy2 = true; // 设置右下角标志为真
	} else if (touchType == "right-top") {
		x2 += ax; // 更新右下角x坐标
		y1 += ay; // 更新左上角y坐标
		cx2 = true; // 设置右下角标志为真
		cy1 = true; // 设置左上角标志为真
	} else if (touchType == "right-bottom") {
		x2 += ax; // 更新右下角x坐标
		y2 += ay; // 更新右下角y坐标
		cx2 = true; // 设置右下角标志为真
		cy2 = true; // 设置右下角标志为真
	}
	if (x1 < image.left) {
		x1 = image.left; // 限制左上角x坐标
	}
	if (y1 < image.top) {
		y1 = image.top; // 限制左上角y坐标
	}
	if (x2 > image.left + image.width) {
		x2 = image.left + image.width; // 限制右下角x坐标
	}
	if (y2 > image.top + image.height) {
		y2 = image.top + image.height; // 限制右下角y坐标
	}
	if (cx1) {
		if (x1 > x2 - mix) {
			x1 = x2 - mix; // 限制左上角x坐标
		}
	}
	if (cy1) {
		if (y1 > y2 - mix) {
			y1 = y2 - mix; // 限制左上角y坐标
		}
	}
	if (cx2) {
		if (x2 < x1 + mix) {
			x2 = x1 + mix; // 限制右下角x坐标
		}
	}
	if (cy2) {
		if (y2 < y1 + mix) {
			y2 = y1 + mix; // 限制右下角y坐标
		}
	}
	if (cx1) {
		if (mode != "free") {
			var val = x2 - rate * (y2 - y1); // 计算限制值
			if (x1 < val) {
				x1 = val; // 限制左上角x坐标
			}
		}
	}
	if (cy1) {
		if (mode != "free") {
			var val = y2 - (x2 - x1) / rate; // 计算限制值
			if (y1 < val) {
				y1 = val; // 限制左上角y坐标
			}
		}
	}
	if (cx2) {
		if (mode != "free") {
			var val = rate * (y2 - y1) + x1; // 计算限制值
			if (x2 > val) {
				x2 = val; // 限制右下角x坐标
			}
		}
	}
	if (cy2) {
		if (mode != "free") {
			var val = (x2 - x1) / rate + y1; // 计算限制值
			if (y2 > val) {
				y2 = val; // 限制右下角y坐标
			}
		}
	}
	frame.left = x1; // 更新框左边距
	frame.top = y1; // 更新框上边距
	frame.width = x2 - x1; // 更新框宽度
	frame.height = y2 - y1; // 更新框高度
	updateStyle(oi); // 更新样式
}
function updateStyle(oi) {
	oi.selectComponent(".frame").setStyle({
		"left": frame.left + "px", // 设置框左边距
		"top": frame.top + "px", // 设置框上边距
		"width": frame.width + "px", // 设置框宽度
		"height": frame.height + "px" // 设置框高度
	});
	oi.selectComponent(".image-wrap").setStyle({
		"left": image.left + "px", // 设置图片左边距
		"top": image.top + "px", // 设置图片上边距
		"width": image.width + "px", // 设置图片宽度
		"height": image.height + "px" // 设置图片高度
	});
	oi.selectComponent(".image-rect").setStyle({
		"left": image.left - frame.left + "px", // 设置图片矩形左边距
		"top": image.top - frame.top + "px", // 设置图片矩形上边距
		"width": image.width + "px", // 设置图片矩形宽度
		"height": image.height + "px" // 设置图片矩形高度
	});
	var left = 0; // 初始化左边距
	var top = 0; // 初始化上边距
	var width = image.width; // 获取图片宽度
	var height = image.height; // 获取图片高度
	if (rotate % 180 != 0) {
		width = image.height; // 旋转后宽度
		height = image.width; // 旋转后高度
		top = width / 2 - height / 2; // 计算上边距
		left = height / 2 - width / 2; // 计算左边距
	}
	oi.selectComponent(".image-wrap .image").setStyle({
		"left": left + "px", // 设置图片左边距
		"top": top + "px", // 设置图片上边距
		"width": width + "px", // 设置图片宽度
		"height": height + "px", // 设置图片高度
		"transform": "rotate(" + rotate + "deg)" // 设置旋转角度
	});
	oi.selectComponent(".image-rect .image").setStyle({
		"left": left + "px", // 设置图片矩形左边距
		"top": top + "px", // 设置图片矩形上边距
		"width": width + "px", // 设置图片矩形宽度
		"height": height + "px", // 设置图片矩形高度
		"transform": "rotate(" + rotate + "deg)" // 设置旋转角度
	});
}
module.exports = {
	changeMode: changeMode,
	changeRotate: changeRotate,
	changeImage: changeImage,
	changeFrame: changeFrame,
	touchstart: touchstart,
	touchmove: touchmove,
	touchend: touchend,
	touchcancel: touchcancel
};
</script>

<style scoped>
.panel {
  position: fixed; /* 固定面板 */
  width: 100%; /* 面板宽度100% */
  height: 100%; /* 面板高度100% */
  top: 0; /* 顶部位置 */
  bottom: 0; /* 底部位置 */
  z-index: 1000; /* 层级 */
  overflow: hidden; /* 隐藏溢出内容 */
}
.canvas {
  position: absolute; /* 绝对定位canvas */
  top: 5000px; /* 隐藏canvas */
  left: 5000px; /* 隐藏canvas */
}
.toolbar {
  position: absolute; /* 绝对定位工具栏 */
  width: 100%; /* 工具栏宽度100% */
  height: 100rpx; /* 工具栏高度 */
  left: 0rpx; /* 左边距 */
  bottom: 0rpx; /* 底部位置 */
  display: flex; /* 使用flex布局 */
  justify-content: space-around; /* 均匀分布 */
  align-items: center; /* 垂直居中 */
}
.btn-cancel {
  font-size: 40rpx; /* 按钮字体大小 */
  color: #d5dfe5; /* 按钮字体颜色 */
  font-weight: bold; /* 按钮字体加粗 */
}
.btn-ok {
  font-size: 40rpx; /* 按钮字体大小 */
  color: #ffffff; /* 按钮字体颜色 */
  font-weight: bold; /* 按钮字体加粗 */
}
.btn-rotate {
  font-size: 40rpx; /* 按钮字体大小 */
  color: #d5dfe5; /* 按钮字体颜色 */
  font-weight: bold; /* 按钮字体加粗 */
}
.body {
  position: absolute; /* 绝对定位body */
  left: 0rpx; /* 左边距 */
  right: 0rpx; /* 右边距 */
  top: 0rpx; /* 顶部位置 */
  bottom: 0rpx; /* 底部位置 */
  background: black; /* 背景颜色 */
  overflow: hidden; /* 隐藏溢出内容 */
}
.mask {
  position: absolute; /* 绝对定位遮罩 */
  left: 0rpx; /* 左边距 */
  right: 0rpx; /* 右边距 */
  top: 0rpx; /* 顶部位置 */
  bottom: 0rpx; /* 底部位置 */
  background: black; /* 背景颜色 */
  opacity: 0.4; /* 遮罩透明度 */
}
.plank {
  position: absolute; /* 绝对定位板 */
  left: 0rpx; /* 左边距 */
  right: 0rpx; /* 右边距 */
  top: 0rpx; /* 顶部位置 */
  bottom: 0rpx; /* 底部位置 */
}
.image-wrap {
  position: absolute; /* 绝对定位图片包裹 */
}
.image-rect {
  position: absolute; /* 绝对定位图片矩形 */
}
.image {
  position: absolute; /* 绝对定位图片 */
}
.frame {
  position: absolute; /* 绝对定位框 */
  left: 100px; /* 左边距 */
  top: 100px; /* 上边距 */
  width: 200px; /* 框宽度 */
  height: 200px; /* 框高度 */
}
.rect {
  position: absolute; /* 绝对定位矩形 */
  left: -2px; /* 左边距 */
  top: -2px; /* 上边距 */
  width: 100%; /* 矩形宽度100% */
  height: 100%; /* 矩形高度100% */
  border: 2px solid white; /* 矩形边框 */
  overflow: hidden; /* 隐藏溢出内容 */
  box-sizing: content-box; /* 盒子模型 */
}
.line-one {
  position: absolute; /* 绝对定位线条 */
  width: 100%; /* 线条宽度100% */
  height: 1px; /* 线条高度 */
  background: white; /* 线条颜色 */
  left: 0; /* 左边距 */
  top: 33.3%; /* 上边距 */
  box-sizing: content-box; /* 盒子模型 */
}
.line-two {
  position: absolute; /* 绝对定位线条 */
  width: 100%; /* 线条宽度100% */
  height: 1px; /* 线条高度 */
  background: white; /* 线条颜色 */
  left: 0; /* 左边距 */
  top: 66.7%; /* 上边距 */
  box-sizing: content-box; /* 盒子模型 */
}
.line-three {
  position: absolute; /* 绝对定位线条 */
  width: 1px; /* 线条宽度 */
  height: 100%; /* 线条高度 */
  background: white; /* 线条颜色 */
  top: 0; /* 上边距 */
  left: 33.3%; /* 左边距 */
  box-sizing: content-box; /* 盒子模型 */
}
.line-four {
  position: absolute; /* 绝对定位线条 */
  width: 1px; /* 线条宽度 */
  height: 100%; /* 线条高度 */
  background: white; /* 线条颜色 */
  top: 0; /* 上边距 */
  left: 66.7%; /* 左边距 */
  box-sizing: content-box; /* 盒子模型 */
}
.frame-left-top {
  position: absolute; /* 绝对定位框左上角 */
  width: 20px; /* 左上角宽度 */
  height: 20px; /* 左上角高度 */
  left: -6px; /* 左边距 */
  top: -6px; /* 上边距 */
  border-left: 4px solid red; /* 左边框 */
  border-top: 4px solid red; /* 上边框 */
  box-sizing: content-box; /* 盒子模型 */
}
.frame-left-bottom {
  position: absolute; /* 绝对定位框左下角 */
  width: 20px; /* 左下角宽度 */
  height: 20px; /* 左下角高度 */
  left: -6px; /* 左边距 */
  bottom: -6px; /* 底部位置 */
  border-left: 4px solid red; /* 左边框 */
  border-bottom: 4px solid red; /* 下边框 */
  box-sizing: content-box; /* 盒子模型 */
}
.frame-right-top {
  position: absolute; /* 绝对定位框右上角 */
  width: 20px; /* 右上角宽度 */
  height: 20px; /* 右上角高度 */
  right: -6px; /* 右边距 */
  top: -6px; /* 上边距 */
  border-right: 4px solid red; /* 右边框 */
  border-top: 4px solid red; /* 上边框 */
  box-sizing: content-box; /* 盒子模型 */
}
.frame-right-bottom {
  position: absolute; /* 绝对定位框右下角 */
  width: 20px; /* 右下角宽度 */
  height: 20px; /* 右下角高度 */
  right: -6px; /* 右边距 */
  bottom: -6px; /* 底部位置 */
  border-right: 4px solid red; /* 右边框 */
  border-bottom: 4px solid red; /* 下边框 */
  box-sizing: content-box; /* 盒子模型 */
}
.transit {
  transition: width 0.3s, height 0.3s, left 0.3s, top 0.3s, transform 0.3s; /* 设置过渡效果 */
}
</style>
